import pdfplumber
import pandas as pd
from pathlib import Path

def batch_extract_pdf_tables(folder_path):
    """批量提取文件夹下所有PDF的表格数据"""
    all_tables = []
    pdf_folder = Path(folder_path)
    
    for pdf_file in pdf_folder.glob('*.pdf'):
        try:
            with pdfplumber.open(pdf_file) as pdf:
                print(f"\n{'='*40}")
                print(f"正在解析文件: {pdf_file.name} (共{len(pdf.pages)}页)")
                for page in pdf.pages:
                    table = page.extract_table({
                        'vertical_strategy': 'lines',
                        'horizontal_strategy': 'lines'
                    })
                    if table:
                        # 打印表格结构
                        print(f"\n第{page.page_number}页表格结构:")
                        print("表头:", table[0])
                        print("示例数据:")
                        for i, row in enumerate(table[1:3]):
                            print(f"行{i+1}: {row}")
                        
                        all_tables.extend(table)
        except Exception as e:
            print(f"\n处理文件 {pdf_file.name} 时遇到错误: {str(e)}")
            continue
    
    return all_tables

def process_data(tables):
    """处理并合并相同行数据"""
    if not tables:
        return pd.DataFrame()
    
    # 自动检测表头（假设所有PDF表格结构相同）
    header = tables[0]
    data = tables[1:]  # 修复：保留所有数据行，不再丢弃最后几行
    print("datadata:",data)
    
    # 查找项目名称列的索引
    project_name_idx = -1
    serial_idx = 0  # 默认序号列为第一列
    for i, col in enumerate(header):
        clean_col = str(col).replace('\n', '').replace(' ', '')
        if '项目名称' in clean_col:
            project_name_idx = i
        elif '序号' in clean_col:
            serial_idx = i
    
    # 改进分页数据合并逻辑
    merged_data = []
    prev_row = None
    prev_is_valid_row = False
    
    for row_idx, row in enumerate(data):
        # 确保row是列表格式
        if not isinstance(row, list):
            row = list(row)
        
        current_serial = row[serial_idx] if len(row) > serial_idx else ''
        # 增强的分页行检测逻辑
        is_pagination_row = False
        
        # 情况1：无序号但有内容的行通常是分页行
        if not current_serial and any(cell and str(cell).strip() for cell in row if cell != current_serial):
            is_pagination_row = True
            print(f"检测到分页行(情况1): 行{row_idx}, 序号='{current_serial}', 内容={row}")
        # 情况2：项目名称列有内容的行（可能是项目名称延续到下一页）
        elif project_name_idx >= 0 and len(row) > project_name_idx and row[project_name_idx] and prev_row and prev_is_valid_row:
            # 如果该项目名称列有内容，而序号列无内容，则认为是分页行
            if not current_serial:
                is_pagination_row = True
                print(f"检测到分页行(情况2): 行{row_idx}, 项目名称='{row[project_name_idx]}'")
        # 情况3：序号列有数字但项目名称列为空的行（可能是项目名称延续到下一页）
        elif (current_serial and 
              str(current_serial).isdigit() and 
              project_name_idx >= 0 and 
              len(row) > project_name_idx and 
              not row[project_name_idx] and 
              prev_row and 
              prev_is_valid_row):
            is_pagination_row = True
            print(f"检测到分页行(情况3): 行{row_idx}, 序号='{current_serial}', 项目名称='{row[project_name_idx]}'")
        # 情况4：序号是连续数字的行（可能是数据行跨页）
        elif (current_serial and str(current_serial).isdigit() and 
              prev_row and prev_is_valid_row and 
              project_name_idx >= 0 and len(prev_row) > project_name_idx and not prev_row[project_name_idx]):
            # 如果前一行是有效数据行但项目名称为空，当前行有序号和项目名称，则可能是跨页数据
            if (len(row) > project_name_idx and row[project_name_idx] and 
                str(row[project_name_idx]).strip()):
                is_pagination_row = True
                print(f"检测到分页行(情况4): 行{row_idx}, 序号='{current_serial}', 项目名称='{row[project_name_idx]}'")
        # 情况5：处理像Terminal#853-856这样第三列内容是上一页数据延续的情况
        # 只有当前行没有有效序号且某列包含换行符内容时，才可能是分页行
        elif (not current_serial and 
              prev_row and prev_is_valid_row):
            # 检查每一列是否可能是上一页数据的延续
            for col_idx, cell_value in enumerate(row):
                if (cell_value and str(cell_value).strip() and 
                    '\n' in str(cell_value) and 
                    len(str(cell_value).split('\n')) > 1 and
                    col_idx != serial_idx):  # 排除序号列
                    # 如果该列内容包含换行符且不是序号列，则可能是上一页数据延续
                    is_pagination_row = True
                    print(f"检测到分页行(情况5): 行{row_idx}, 列{col_idx} 包含跨页数据: '{cell_value}'")
                    break
        
        # 判断当前行是否为有效数据行（有有效序号）
        is_valid_row = bool(current_serial and str(current_serial).isdigit())
        
        if is_pagination_row and prev_row:
            # 增强合并逻辑，特别处理项目名称字段和其他有内容的字段
            for i in range(len(row)):
                if i < len(prev_row) and row[i]:  # 确保索引有效且内容非空
                    # 对于项目名称列，总是合并（即使是分页行也有可能有部分内容）
                    if i == project_name_idx and row[i]:
                        if prev_row[i]:  # 前一行该列有内容，进行合并
                            prev_row[i] = str(prev_row[i]).strip() + ' ' + str(row[i]).strip()
                        else:  # 前一行该列无内容，直接赋值
                            prev_row[i] = str(row[i]).strip()
                        print(f"合并项目名称: 行{row_idx} '{row[i]}' -> '{prev_row[i]}'")
                    # 对于其他列，只有在特定条件下才合并
                    elif row[i] and str(row[i]).strip():
                        # 特别处理包含换行符的内容（如Terminal#853-856的情况）
                        cell_content = str(row[i]).strip()
                        # 如果内容包含换行符，先处理换行符
                        if '\n' in cell_content:
                            # 将换行符替换为空格，使内容更易读
                            cell_content = ' '.join(cell_content.split('\n'))
                        
                        # 如果前一行该列已经有内容，则追加
                        if prev_row[i] and str(prev_row[i]).strip():
                            prev_row[i] = str(prev_row[i]).strip() + ' ' + cell_content
                        else:  # 前一行该列无内容，直接赋值
                            prev_row[i] = cell_content
        else:
            if prev_row:
                print(f"添加完整行{len(merged_data)+1}: {prev_row}")
                merged_data.append(prev_row)
            prev_row = list(row) if row else []
            prev_is_valid_row = is_valid_row
    
    # 添加最后一行
    if prev_row:
        print(f"添加最后一行: {prev_row}")
        merged_data.append(prev_row)
    
    # 在创建DataFrame后立即执行全局列名清理
    df = pd.DataFrame(merged_data, columns=header)
    df.columns = df.columns.str.replace(r'[\n\s]+', '', regex=True)  # 新增列名清理
    
    # 后续字段映射保持原逻辑
    df = df.rename(columns={
        '项目单位/收货方': '收货单位',
        '数量': '数量',          # 确保清理后的列名匹配
        '项目\n单位/收货方': '收货单位',
        '项目名\n称': '项目名称',
        '货物\n名称': '货物名称',
        '规格\n型号': '规格型号',
        '分项价\n(不含税）': '合同金额',
        '交货\n时间': '送货时间',
        '不含\n税\n单价': '不含税单价'
    }, errors='ignore')

    print("df.columns",df.columns)
    # 生成必要字段
    if '订单编号' not in df.columns:
        df['订单编号'] = 'XD' + df['序号'].astype(str).str.zfill(6)
        
    # 处理数值字段
    print("df['数量'].str.replace('\n', '')111:",df['数量'])
    print("df['数量'].str.replace('\n', ''):",df['数量'].str.replace('\n', ''))
    df['数量'] = df['数量'].str.replace('\n', '').astype(int)
    df['合同金额'] = df['分项价（含税）'].str.replace('[^\d.]', '', regex=True).astype(float)
    # df['送货金额'] = df['合同金额'] * 1.13  # 计算含税金额
    df['送货数'] = df['数量']  # 同步送货数

    # 更新数值列列表
    numeric_cols = ['数量', '合同金额', '送货金额']
    
    # 智能合并相同行（根据实际业务字段调整）
    merge_columns = ['合同编号', '客户名称']  # 关键合并字段
    numeric_cols = df.select_dtypes(include='number').columns.tolist()
    
    # 添加字段映射（根据实际PDF字段调整）
    # 修正字段映射关系（根据实际PDF表头）
    df = df.rename(columns={
        '项目\n单位/收货方': '收货单位',  # 确保匹配原始列名中的换行符
        '项目单位/收货方': '收货单位',   # 添加备用匹配（处理可能的空格转换）
        '规格\n型号': '型号',
        '数\n量': '数量',
        '分项价\n(不含税）': '合同金额',
        '交货\n时间': '送货时间',
        '不含\n税\n单价': '不含税单价'
    }, errors='ignore')  # 添加错误忽略参数
    
    # 添加列名验证
    if '收货单位' not in df.columns:
        print("列名匹配异常，实际列名：", df.columns.tolist())
        df['收货单位'] = df.iloc[:, 1]  # 备选方案：按列位置获取

    # 地区提取逻辑增加容错
    df['地区'] = df.get('收货单位', '').str.extract(r'(陕西|北京|上海|广州)')
    
    # 智能合并相同行字段调整
    merge_columns = ['序号', '收货单位']  # 根据实际业务标识字段
    numeric_cols = df.select_dtypes(include='number').columns.tolist()
    
    # 增强字段映射兼容性
    # df = df.rename(columns={
    #     r'项目[\n\s]*单位/收货方': '收货单位',
    #     r'数[\n\s]*量': '数量',  # 正则匹配含换行/空格的列名
    #     r'Quantity|QTY': '数量'  # 添加英文列名匹配
    # }, regex=True, errors='ignore')

    # 列存在性检查
    if '数量' not in df.columns:
        print("⚠️ 未检测到数量字段，实际列名：", df.columns.tolist())
        # 按列位置获取（假设数量在第5列）
        df['数量'] = df.iloc[:, 4] if len(df.columns) > 4 else 0

    # 增强数值清洗逻辑
    if '数量' in df.columns:
        df['数量'] = (
            df['数量']
            .astype(str)
            .str.replace(r'[^\d]', '', regex=True)  # 移除非数字字符
            .replace('', '0')  # 处理空值
            .astype(int)
        )

    # 增强规格型号列清洗逻辑
    if '规格型号' in df.columns:
        df['规格型号'] = (
            df['规格型号']
            .astype(str)
            .str.replace(r'[\n\s]+', ' ', regex=True)  # 将换行符和连续空白字符替换为单个空格
            .str.replace(r'\s*([,])\s*', r'\1', regex=True)  # 去除逗号前后的空格
            .str.strip()  # 去除首尾空格
            .str.replace(r'(?<=\S)\s+(?=\S)', '', regex=True)  # 移除汉字/字符之间的单个空格
            .replace('', '无规格型号')  # 处理空值
        )
        
    # 增强项目名称和货物名称列清洗逻辑
    text_columns = ['项目名称', '货物名称']
    for col in text_columns:
        if col in df.columns:
            df[col] = (
                df[col]
                .astype(str)
                .str.replace(r'[\n\s]+', ' ', regex=True)  # 将换行符和连续空白字符替换为单个空格
                .str.strip()  # 去除首尾空格
                .str.replace(r'(?<=\S)\s+(?=\S)', '', regex=True)  # 移除汉字/字符之间的单个空格
            )

    # 清洗无效数据行（匹配实际表格中的"总计"行）
    df = df[~df['序号'].str.contains('总计', na=False)]

    # 生成必要字段的容错处理
    required_columns = {
        '订单编号': ('序号', lambda x: 'XD' + str(x).zfill(6)),
        '送货数': ('数量', lambda x: x),
        '合同金额': (r'分项价[\n\s]*(不含税)', lambda x: x)
    }
    
    for new_col, (src_col, func) in required_columns.items():
        if new_col not in df.columns:
            if src_col in df.columns:
                df[new_col] = df[src_col].apply(func)
            else:
                print(f"无法生成字段 {new_col}, 缺失源字段 {src_col}")

    # 添加类型转换确保数值列正确处理
    for col in numeric_cols:
        df[col] = pd.to_numeric(df[col], errors='coerce')

    # 执行合并
    # merged_df = df.groupby(merge_columns, as_index=False).agg(agg_rules)
    
    print(f"\n合并后统计:")
    # print(f"合并行数: {len(merged_df)}")
    print(f"合并依据字段: {merge_columns}")
    
    return df.columns

def save_to_excel(df, output_path):
    """保存到Excel文件（保持34行格式）"""
    if df.empty:
        print("未找到有效数据")
        return

    # 按新顺序排列列（需确保DataFrame包含这些字段）
    target_columns = [
        '订单编号',    # 原合同编号
        '地区',        # 需确认数据源存在该字段
        '收货单位',    # 原客户名称
        '项目名称', 
        '型号',
        '数量',
        '送货数',
        '送货金额',
        '送货时间',
        '合同金额'     # 原分项价(不含税）
    ]
    
    with pd.ExcelWriter(output_path, engine='xlsxwriter') as writer:
        # 按新列顺序输出
        df[target_columns].to_excel(writer, index=False, sheet_name='合同汇总')
        
        # 格式设置
        workbook = writer.book
        worksheet = writer.sheets['合同汇总']
        
        # 调整列宽设置
        column_widths = {
            '订单编号': 15,   # A列
            '地区': 10,       # B列  
            '收货单位': 25,   # C列
            '项目名称': 20,   # D列
            '型号': 15,       # E列
            '数量': 8,        # F列
            '送货数': 8,      # G列
            '送货金额': 12,   # H列
            '送货时间': 12,   # I列
            '合同金额': 15    # J列
        }
        
        # 应用列宽设置
        for col_num, col_name in enumerate(target_columns):
            if col_name in column_widths:
                worksheet.set_column(col_num, col_num, column_widths[col_name])
        
        # 设置列宽（根据34行格式要求）
        worksheet.set_column('A:A', 15)   # 合同编号
        worksheet.set_column('B:B', 25)   # 客户名称
        worksheet.set_column('C:Z', 12)   # 其他列

    # 添加全局列名清理（在所有重命名操作之后）
    df.columns = df.columns.str.replace(r'\n', '', regex=True).replace(r'[\n\s]+', ' ', regex=True).strip()  # 移除非列名中的换行符
    
    # 原字段映射和数值处理代码保持不变
    if '数量' not in df.columns:
        print("⚠️ 未检测到数量字段，实际列名：", df.columns.tolist())
        # 按列位置获取（假设数量在第5列）
        df['数量'] = df.iloc[:, 4] if len(df.columns) > 4 else 0

    # 增强数值清洗逻辑
    if '数量' in df.columns:
        df['数量'] = (
            df['数量']
            .astype(str)
            .str.replace(r'[^\d]', '', regex=True)  # 移除非数字字符
            .replace('', '0')  # 处理空值
            .astype(int)
        )
    
    # 清洗无效数据行（匹配实际表格中的"总计"行）
    df = df[~df['序号'].str.contains('总计', na=False)]

    # 生成必要字段的容错处理
    required_columns = {
        '订单编号': ('序号', lambda x: 'XD' + str(x).zfill(6)),
        '送货数': ('数量', lambda x: x),
        '合同金额': (r'分项价[\n\s]*(不含税)', lambda x: x)
    }
    print("df.columns",df.columns)
    for new_col, (src_col, func) in required_columns.items():
        if new_col not in df.columns:
            if src_col in df.columns:
                df[new_col] = df[src_col].apply(func)
            else:
                print(f"无法生成字段 {new_col}, 缺失源字段 {src_col}")

    # 添加类型转换确保数值列正确处理
    for col in numeric_cols:
        df[col] = pd.to_numeric(df[col], errors='coerce')

    # 执行合并
    # merged_df = df.groupby(merge_columns, as_index=False).agg(agg_rules)
    
    print(f"\n合并后统计:")
    # print(f"合并行数: {len(merged_df)}")
    print(f"合并依据字段: {merge_columns}")
    
    return df.columns

def save_to_excel(df, output_path):
    """保存到Excel文件（保持34行格式）"""
    if df.empty:
        print("未找到有效数据")
        return

    # 按新顺序排列列（需确保DataFrame包含这些字段）
    target_columns = [
        '订单编号',    # 原合同编号
        '地区',        # 需确认数据源存在该字段
        '收货单位',    # 原客户名称
        '项目名称', 
        '型号',
        '数量',
        '送货数',
        '送货金额',
        '送货时间',
        '合同金额'     # 原分项价(不含税）
    ]
    
    with pd.ExcelWriter(output_path, engine='xlsxwriter') as writer:
        # 按新列顺序输出
        df[target_columns].to_excel(writer, index=False, sheet_name='合同汇总')
        
        # 格式设置
        workbook = writer.book
        worksheet = writer.sheets['合同汇总']
        
        # 调整列宽设置
        column_widths = {
            '订单编号': 15,   # A列
            '地区': 10,       # B列  
            '收货单位': 25,   # C列
            '项目名称': 20,   # D列
            '型号': 15,       # E列
            '数量': 8,        # F列
            '送货数': 8,      # G列
            '送货金额': 12,   # H列
            '送货时间': 12,   # I列
            '合同金额': 15    # J列
        }
        
        # 应用列宽设置
        for col_num, col_name in enumerate(target_columns):
            if col_name in column_widths:
                worksheet.set_column(col_num, col_num, column_widths[col_name])
        
        # 设置列宽（根据34行格式要求）
        worksheet.set_column('A:A', 15)   # 合同编号
        worksheet.set_column('B:B', 25)   # 客户名称
        worksheet.set_column('C:Z', 12)   # 其他列

# 配置路径
input_folder = Path("小合同")      # PDF文件夹路径
output_file = Path("百信达匹配.xlsx")  # 输出文件

# 执行处理流程
print("开始解析PDF表格...")
all_tables = batch_extract_pdf_tables(input_folder)
print("\n解析完成，共提取到{}行数据".format(len(all_tables)))

# 打印完整表头结构
if all_tables:
    print("\n最终合并表头结构:")
    print(all_tables[0])
    print("\n前3行示例数据:")
    for i, row in enumerate(all_tables[1:4]):
        print(f"行{i+1}: {row}")

processed_df = process_data(all_tables)
save_to_excel(processed_df, output_file)

# 在执行流程最后增加数据预览
print("\n最终处理结果预览:")
print(f"总数据行数: {len(processed_df)}")
print("\n表头结构:")
print(processed_df.columns.tolist())
print("\n前5行数据示例:")
print(processed_df.head().to_string(index=False))

# 针对特定字段的额外处理
if '交货地点及交货方式' in df.columns:
    df['交货地点及交货方式'] = df['交货地点及交货方式'].str.replace('\n', '')

    # 修改字段映射关系（匹配含税金额）
    df = df.rename(columns={
        r'分项价[\n\s]*(含税)': '合同金额',  # 新增含税金额匹配
        r'分项价[\n\s]*(不含税)': '合同金额'  # 保留原有匹配
    }, regex=True, errors='ignore')

    # 更新数值处理逻辑
    if '合同金额' in df.columns:
        df['合同金额'] = (
            df['合同金额']
            .astype(str)
            .str.replace(r'[^\d.]', '', regex=True)  # 保留数字和小数点
            .astype(float)
        )

    # 调整金额计算说明
    df['送货金额'] = df['合同金额']  # 根据需求直接同步金额